package com.workcell.workdata.xthings.service.impl.mqtt;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.workcell.workdata.xthings.dto.CodeChainnumVo;
import com.workcell.workdata.xthings.dto.ReturnDataVO;
import com.workcell.workdata.xthings.entity.mqtt.FlowMeterData;
import com.workcell.workdata.xthings.mapper.mqtt.FlowMeterDataMapper;
import com.workcell.workdata.xthings.service.FlowMeterRealDataService;
import com.workcell.workdata.xthings.service.factory.HardwareRealDataService;
import com.workcell.workdata.xthings.utils.DateTimeUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author 廖博文
 * @Date 2022/12/5 14:16
 * @Description 流量计真实数据
 */
@Service
@DS("slave_flow")
@RequiredArgsConstructor
public class FlowMeterRealDataServiceImpl extends ServiceImpl<FlowMeterDataMapper, FlowMeterData> implements HardwareRealDataService, FlowMeterRealDataService {

	private final RedisTemplate redisTemplate;
	private final String baseCodeBaseRedisKey = "DataQrCode_FlowMeter_DataHourLineChartInfo_%s_%s";
	private final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");

	/**
	 * 获取硬件最近的一次数据
	 * @param deviceNo 设备编号
	 * @param time
	 * @return
	 */
	@Override
	public Object getLatelyDataInfo(String deviceNo, String manufacturerCode, Integer time) {
		return this.baseMapper.getLatelyDataInfoByDeviceNo(deviceNo, manufacturerCode, time);
	}

	/**
	 * 获取硬件最近六个小时的数据：折线图
	 * @param deviceNo
	 * @return
	 */
	@Override
	public Object getDataHourLineChartInfo(String deviceNo, String manufacturerCode) {
		Map<String, FlowMeterData> dbFlowMeterData = new LinkedHashMap<>(6);
		// 获取当前小时时间
		Date nowHourTime = DateTimeUtil.addHourAndFormatSM(0);
		Date nowHourTimeAddOne = DateTimeUtil.addHourAndFormatSM(1);
		checkRedisSearchDbDataChar(dbFlowMeterData, deviceNo, manufacturerCode, nowHourTime, nowHourTimeAddOne);
		// 处理一个小时前的数据
		Date nowHourTimeSub1 = DateTimeUtil.addHourAndFormatSM(-1);
		checkRedisSearchDbDataChar(dbFlowMeterData, deviceNo, manufacturerCode, nowHourTimeSub1, nowHourTime);
		// 处理两个小时前的数据
		Date nowHourTimeSub2 = DateTimeUtil.addHourAndFormatSM(-2);
		checkRedisSearchDbDataChar(dbFlowMeterData, deviceNo, manufacturerCode, nowHourTimeSub2, nowHourTimeSub1);
		// 处理三个小时前的数据
		Date nowHourTimeSub3 = DateTimeUtil.addHourAndFormatSM(-3);
		checkRedisSearchDbDataChar(dbFlowMeterData, deviceNo, manufacturerCode, nowHourTimeSub3, nowHourTimeSub2);
		// 处理四个小时前的数据
		Date nowHourTimeSub4 = DateTimeUtil.addHourAndFormatSM(-4);
		checkRedisSearchDbDataChar(dbFlowMeterData, deviceNo, manufacturerCode, nowHourTimeSub4, nowHourTimeSub3);
		// 处理五个小时前的数据
		Date nowHourTimeSub5 = DateTimeUtil.addHourAndFormatSM(-5);
		checkRedisSearchDbDataChar(dbFlowMeterData, deviceNo, manufacturerCode, nowHourTimeSub5, nowHourTimeSub4);
		// 组装数据
		JSONArray typeArray = new JSONArray();
		typeArray.add("瞬时流量");
		typeArray.add("累计流量");
		JSONArray timeArray = new JSONArray();
		JSONArray informationArray = new JSONArray();
		JSONObject flowRateObject = new JSONObject();
		JSONObject cumFlowObject = new JSONObject();
		flowRateObject.put("name","瞬时流量");
		cumFlowObject.put("name","累计流量");
		JSONArray flowRaterArray = new JSONArray();
		JSONArray cumFlowArray = new JSONArray();
		// 逆序遍历
		ListIterator<Map.Entry<String,FlowMeterData>> i =
				new ArrayList<>(dbFlowMeterData.entrySet()).listIterator(dbFlowMeterData.size());
		while(i.hasPrevious()) {
			Map.Entry<String, FlowMeterData> entry = i.previous();
			timeArray.add(entry.getKey());
			flowRaterArray.add(entry.getValue().getFlowRate());
			cumFlowArray.add(entry.getValue().getCumFlow());
		}
		flowRateObject.put("data",flowRaterArray);
		cumFlowObject.put("data",cumFlowArray);
		informationArray.add(flowRateObject);
		informationArray.add(cumFlowObject);
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("typeArray",typeArray);
		jsonObject.put("timeArray",timeArray);
		jsonObject.put("informationArray",informationArray);
		return jsonObject;
	}




	/**
	 * 判断redis存在当前时间段的缓存，否则查询库存储
	 * @param dbFlowMeterData 查询的信息存储
	 * @param deviceNo 设备编号
	 * @param nowHourTime 开始时间
	 * @param nowHourTimeAddOne 结束时间
	 */
	public void checkRedisSearchDbDataChar(Map<String, FlowMeterData> dbFlowMeterData, String deviceNo, String manufacturerCode, Date nowHourTime, Date nowHourTimeAddOne){
		Object nowHourTimeDate = redisTemplate.opsForValue().get(String.format(baseCodeBaseRedisKey,deviceNo,nowHourTime));
		if (ObjectUtil.isEmpty(nowHourTimeDate)){
			nowHourTimeDate = this.baseMapper.getDataHourLineChartInfo(deviceNo, manufacturerCode, nowHourTime, nowHourTimeAddOne);
			if (ObjectUtil.isNotEmpty(nowHourTimeDate)){
				redisTemplate.opsForValue().set(String.format(baseCodeBaseRedisKey,deviceNo,nowHourTime),nowHourTimeDate,1, TimeUnit.DAYS);
			}
		}
		dbFlowMeterData.put(sdf.format(nowHourTime),ObjectUtil.isEmpty(nowHourTimeDate)?new FlowMeterData():(FlowMeterData)nowHourTimeDate);
	}

	@Override
    public Page<FlowMeterData> getHardwareDataInfo(CodeChainnumVo.SelectChainNumDataVo selectChainNumDataVo) {
		LambdaQueryWrapper<FlowMeterData> queryWrapper = new QueryWrapper<FlowMeterData>().lambda()
				.eq(ObjectUtil.isNotEmpty(selectChainNumDataVo.getDeviceNo()),FlowMeterData::getDeviceNo,selectChainNumDataVo.getDeviceNo())
				.eq(ObjectUtil.isNotEmpty(selectChainNumDataVo.getManufacturerCode()),FlowMeterData::getManufacturerCode,selectChainNumDataVo.getManufacturerCode())
				.and(ObjectUtil.isNotEmpty(selectChainNumDataVo.getStartTime()) || ObjectUtil.isNotEmpty(selectChainNumDataVo.getEndTime()),
						i -> i.between(FlowMeterData::getCreateDate,selectChainNumDataVo.getStartTime(),selectChainNumDataVo.getEndTime()));

		Page<FlowMeterData> page = new Page<>(selectChainNumDataVo.getPageNum(), selectChainNumDataVo.getPageSize());
		page.addOrder(OrderItem.desc("create_date"));
		return this.page(page,queryWrapper);

	}

	@Override
	public Object getRealData(String deviceNo) {
		LocalDateTime endTime = LocalDateTimeUtil.now();
		LocalDateTime startTime = LocalDateTimeUtil.offset(endTime, -1, ChronoUnit.MINUTES);
		LambdaQueryWrapper<FlowMeterData> lambdaQueryWrapper = Wrappers.lambdaQuery(FlowMeterData.class);
		lambdaQueryWrapper.eq(FlowMeterData::getDeviceNo,deviceNo);
		lambdaQueryWrapper.between(FlowMeterData::getCreateDate,startTime,endTime);
		lambdaQueryWrapper.orderByDesc(FlowMeterData::getCreateDate);
		return this.getOne(lambdaQueryWrapper);
	}

	public FlowMeterData returnFlowMeterData(ReturnDataVO returnDataVO) {
		Assert.isTrue(ObjectUtil.isNotEmpty(returnDataVO.getDeviceNo()),"设备编码不能为空");
		FlowMeterData dataHourInfo = this.baseMapper.getDataHourInfo(returnDataVO.getDeviceNo(), returnDataVO.getManufacturerCode(), returnDataVO.getStartTime(), returnDataVO.getEndTime());
		return dataHourInfo;

	}
}
